package com.hutgin2.core.meta;

import org.hibernate.annotations.Index;

import javax.persistence.*;

@Entity
@Table(name = "META_FIELD")
public class FieldMeta extends MetaEntity {

    @Id
    @Column(length = 501)
    public String getId() {
        return tableName + "." + name;
    }

    public void setId(String id) {

    }

    private String name;

    private String fieldName;


    private String tableName;

    private Class type;

    private Integer size;

    private Integer precision;

    private TableMeta table;

    private FieldAssociationType associationType = FieldAssociationType.NONE;

    private FieldMeta fieldRef;

    private boolean required;


    /**
     * Simplify primary key, can be only one field as primary key and corresponding table doesn't contain PK constraint.
     * Corresponding constraint in table constraints list will be autopopulated (and replaced if exists any other PK) as transient read-only.
     * PrimaryKey name is autogenerated.
     * TODO implement check that table has only one pk
     * TODO implement autoPopulate method for table which will populate constraints with PK,UQ,FKs
     */
    private boolean primaryKey;

    /**
     * Simplify unique constraint. Corresponding table doesn't contain UQ constraint, even if contains those constraint will be ignored.
     * Corresponding constraint in table constraints list will be autopopulated (and replaced if exists any other UQ) as transient read-only.
     * Unique contraint name is autogenerated.
     */
    private boolean uniq;


    private ValueGenerationStrategy insertGenerationStrategy = ValueGenerationStrategy.NONE;

    private ValueGenerationStrategy updateGenerationStrategy = ValueGenerationStrategy.NONE;

    /**
     * Class name that implement Generator interface,
     * can be for primary key or any field.
     * If insertGenerationStrategy = DEFAULT_VALUE this field contains default value.
     * TODO HibernateIdentifierGeneratorBridge
     * TODO список доступных генераторов (все что унаследовано от Generator) и доступно как параметр для HibernateIdentifierGeneratorBridge
     */
    private String insertGenerator;

    /**
     * Class name that implement Generator interface,
     * can be for primary key or any field.
     * If updateGenerationStrategy = DEFAULT_VALUE this field contains default value.
     * TODO HibernateIdentifierGeneratorBridge
     * TODO список доступных генераторов (все что унаследовано от Generator) и доступно как параметр для HibernateIdentifierGeneratorBridge
     */
    private String updateGenerator;

    /**
     * Determines that corresponding column in DB is not presented.
     */
    private boolean virtual = false;

    @Column(length = 255, nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(length = 255)
    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    @Index(name = "IDX_META_FIELD_TYPE")
    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    @ManyToOne
    public TableMeta getTable() {
        return table;
    }

    public void setTable(TableMeta table) {
        this.table = table;
        if (table != null)
            this.tableName = table.getName();
    }

    public Integer getPrecision() {
        return precision;
    }

    public void setPrecision(Integer precision) {
        this.precision = precision;
    }


    @Column(insertable = false, updatable = false, name = "table_name")
    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    @Enumerated(EnumType.STRING)
    @Index(name = "IDX_META_FIELD_ASSOCIATION_TYPE")
    public FieldAssociationType getAssociationType() {
        return associationType;
    }

    public void setAssociationType(FieldAssociationType associationType) {
        this.associationType = associationType;
    }

    @ManyToOne(optional = true)
    public FieldMeta getFieldRef() {
        return fieldRef;
    }

    public void setFieldRef(FieldMeta fieldRef) {
        this.fieldRef = fieldRef;
    }

    public boolean isRequired() {
        return required;
    }

    public void setRequired(boolean required) {
        this.required = required;
    }

    @Enumerated(EnumType.ORDINAL)
    public ValueGenerationStrategy getInsertGenerationStrategy() {
        return insertGenerationStrategy;
    }

    public void setInsertGenerationStrategy(ValueGenerationStrategy insertGenerationStrategy) {
        this.insertGenerationStrategy = insertGenerationStrategy;
    }

    @Enumerated(EnumType.ORDINAL)
    public ValueGenerationStrategy getUpdateGenerationStrategy() {
        return updateGenerationStrategy;
    }

    public void setUpdateGenerationStrategy(ValueGenerationStrategy updateGenerationStrategy) {
        this.updateGenerationStrategy = updateGenerationStrategy;
    }

    public String getInsertGenerator() {
        return insertGenerator;
    }

    public void setInsertGenerator(String insertGenerator) {
        this.insertGenerator = insertGenerator;
    }

    public String getUpdateGenerator() {
        return updateGenerator;
    }

    public void setUpdateGenerator(String updateGenerator) {
        this.updateGenerator = updateGenerator;
    }

    public boolean isPrimaryKey() {
        return primaryKey;
    }

    public void setPrimaryKey(boolean primaryKey) {
        this.primaryKey = primaryKey;
    }

    public boolean isUniq() {
        return uniq;
    }

    public void setUniq(boolean uniq) {
        this.uniq = uniq;
    }

    public boolean isVirtual() {
        return virtual;
    }

    public void setVirtual(boolean virtual) {
        this.virtual = virtual;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        FieldMeta fieldMeta = (FieldMeta) o;

        if (!name.equals(fieldMeta.name)) return false;
        if (!tableName.equals(fieldMeta.tableName)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + tableName.hashCode();
        return result;
    }


    private boolean isProcessed;

    @Transient
    @Deprecated
    public boolean isProcessed() {
        return isProcessed;
    }

    public void setProcessed(boolean processed) {
        isProcessed = processed;
    }

    @Transient
    public String getInsertDefaultValue() {
        switch (this.insertGenerationStrategy) {
            case DEFAULT_VALUE:
                return this.getInsertGenerator();
            default:
                return null;
        }
    }
}
